﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Nomad.Archive.SevenZip;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Diagnostics;

namespace Sublight.Plugins.SubtitleProvider.BuiltIn
{
    class UnCompress
    {
        public static string uncompressFileToStream(string filename, uint FileNumber, Stream outputSt)
        {
            try
            {           
                using (SevenZipFormat Format = new SevenZipFormat(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "7z.dll")))
                {
                    KnownSevenZipFormat format = GetArchiveFormat(filename);
                    IInArchive Archive = Format.CreateInArchive(SevenZipFormat.GetClassIdFromKnownFormat(format));
                    if (Archive == null)
                    {
                        Trace.Write("CreateInArchive error: ");
                        return null;
                    }

                    try
                    {
                        using (InStreamWrapper ArchiveStream = new InStreamWrapper(File.OpenRead(filename)))
                        {
                            ulong CheckPos = 32 * 1024;
                            if (Archive.Open(ArchiveStream, ref CheckPos, null) != 0)
                            {
                                Trace.Write("check error: ");
                                return null;
                            }

                            Trace.Write("Archive: ");
                            Trace.WriteLine(filename);

                            PropVariant Name = new PropVariant();
                            
                            Archive.GetProperty(FileNumber, ItemPropId.kpidPath, ref Name);
                            string FileName = (string)Name.GetObject();

                            Trace.Write("Extracting: ");
                            Trace.Write(FileName);
                            Trace.Write(' ');
                            ArchiveCallback callback = new ArchiveCallback(FileNumber, FileName, outputSt);
                            Archive.Extract(new uint[] { FileNumber }, 1, 0, callback);
                            return FileName;
                        }
                    }
                    finally
                    {
                        Marshal.ReleaseComObject(Archive);
                    }
                }
            }
            catch (Exception e)
            {
                Trace.Write("Error: ");
                Trace.WriteLine(e.Message);
            }
            return null;
        }

        public static KnownSevenZipFormat GetArchiveFormat(string archivePath)
        {

            FileInfo archFile = new FileInfo(archivePath);
            switch (archFile.Extension.ToUpper().Remove(archFile.Extension.IndexOf('.'), 1))
            {
                case "RAR":
                    return KnownSevenZipFormat.Rar;
                case "ZIP":
                    return KnownSevenZipFormat.Zip;
                case "7Z":
                    return KnownSevenZipFormat.SevenZip;
                case "LZH":
                    return KnownSevenZipFormat.Lzh;
                case "Z":
                    return KnownSevenZipFormat.Z;
                case "LZMA":
                    return KnownSevenZipFormat.Lzma;
                case "CBR":
                    return KnownSevenZipFormat.Rar;
                case "CBZ":
                    return KnownSevenZipFormat.Zip;
                default:
                    return KnownSevenZipFormat.UNKNOW;
            }
        }
    }
    class ArchiveCallback : IArchiveExtractCallback
    {
        private uint FileNumber;
        private string FileName;
        private OutStreamWrapper FileStream;
        private Stream outputStream;

        public Stream OutputStream
        {
            get { return outputStream; }
            set { outputStream = value; }
        }

        public ArchiveCallback(uint fileNumber, string fileName, Stream outputStreamP)
        {
            this.FileNumber = fileNumber;
            this.FileName = fileName;
            this.outputStream = outputStreamP;
        }

        #region IArchiveExtractCallback Members

        public void SetTotal(ulong total)
        {
            Trace.WriteLine("total: " + total);
        }

        public void SetCompleted(ref ulong completeValue)
        {
            Trace.WriteLine("completeValue: " + completeValue);
        }

        public int GetStream(uint index, out ISequentialOutStream outStream, AskMode askExtractMode)
        {
            if ((index == FileNumber) && (askExtractMode == AskMode.kExtract))
            {
                FileStream = new OutStreamWrapper(outputStream);
                outStream = FileStream;
            }
            else
                outStream = null;

            return 0;
        }

        public void PrepareOperation(AskMode askExtractMode)
        {
            Trace.WriteLine("askExtractMode: " + askExtractMode);
        }

        public void SetOperationResult(OperationResult resultEOperationResult)
        {
            Trace.WriteLine("OperationResult: " + resultEOperationResult);
            FileStream.Dispose();
        }

        #endregion
    }


}
